package com.tl.satoken.service;

import com.tl.satoken.domain.entity.*;
import com.tl.satoken.mapper.UserMapper;
import jakarta.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

@Service
public class RoomService {
    private static final Logger log = LoggerFactory.getLogger(RoomService.class);

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    @Autowired
    private UserMapper userMapper;

    // 为每个房间维护一个锁，防止并发抢金币
    private final Map<String, ReentrantLock> roomLocks = new ConcurrentHashMap<>();

    public RoomService() {
    }

    @PostConstruct
    public void init() {
        this.cleanupOldData();
    }

    private void cleanupOldData() {
        try {
            log.info("清理旧的游戏数据...");
            Set<String> keys = this.redisTemplate.keys("game:*");
            if (keys != null && !keys.isEmpty()) {
                this.redisTemplate.delete(keys);
                log.info("清理了 {} 个旧的游戏数据", keys.size());
            }
        } catch (Exception e) {
            log.warn("清理旧数据时出现异常: {}", e.getMessage());
        }
    }

    public RoomJoinResult joinRoom(Player player) {
        try {
            // 检查同一个英雄是否已经登录
            String heroKey = "game:hero:" + player.getHeroId();
            if (Boolean.TRUE.equals(this.redisTemplate.hasKey(heroKey))) {
                return new RoomJoinResult(false, "同一个英雄不能同时登陆", null);
            }

            String targetRoomId = this.findAvailableRoom();  // 找到一个可用，并且人数最多的房间
            if (targetRoomId == null) {
                targetRoomId = this.createNewRoom();  // 返回 Room_1
                log.info("创建新房间: {}", targetRoomId);
            }

            String roomKey = "game:room:" + targetRoomId;   // game:room:Room_1
            
            // 使用原子操作检查并添加，避免竞态条件(添加heroId到set中不会遇到竞争问题)上线环境不会允许一个玩家的两个英雄加入到游戏中
            Long addResult = this.redisTemplate.opsForSet().add(roomKey, player.getHeroId());   // 添加 heroId 到 set 中
            if (addResult == 0) {
                // 玩家已经存在于房间中
                return new RoomJoinResult(false, "玩家已在房间中", targetRoomId);
            }
            
            // 检查添加后房间人数是否超过限制
            Long roomSize = this.redisTemplate.opsForSet().size(roomKey);
            if (roomSize != null && roomSize > 5L) {
                // 如果超过限制，移除刚添加的玩家
                this.redisTemplate.opsForSet().remove(roomKey, player.getHeroId());
                return new RoomJoinResult(false, "房间已满", null);
            }

            // 不再在加入时分配金老鼠，由定时任务统一处理
            player.setMouse(false);
            player.setPosition(player.getPosition());
            player.setRoomId(targetRoomId);
            this.redisTemplate.opsForValue().set(heroKey, targetRoomId);
            
            String playerHashKey = "game:player:" + player.getHeroId() + ":data";
            Map<String, Object> playerData = new HashMap<>();

            // 基本字段
            playerData.put("id", player.getId());
            playerData.put("heroId", player.getHeroId());
            playerData.put("animation", player.getAnimation());
            playerData.put("roomId", player.getRoomId());
            playerData.put("sessionId", player.getSessionId());
            playerData.put("isMouse", false);

            // 位置信息
            Position position = player.getPosition();
            if (position != null) {
                Map<String, Float> positionMap = new HashMap<>();
                positionMap.put("x", position.getX());
                positionMap.put("y", position.getY());
                positionMap.put("z", position.getZ());
                playerData.put("position", positionMap);
            }

            // 旋转信息
            Rotation rotation = player.getRotation();
            if (rotation != null) {
                Map<String, Float> rotationMap = new HashMap<>();
                rotationMap.put("y", rotation.getY());
                playerData.put("rotation", rotationMap);
            }

            // 一次性存储所有Hash字段
            this.redisTemplate.opsForHash().putAll(playerHashKey, playerData);
            
            log.info("玩家 {} 成功加入房间 {}, 当前房间人数: {}", player.getHeroId(), targetRoomId, this.getRoomPlayerCount(targetRoomId));
            return new RoomJoinResult(true, "加入成功", targetRoomId);
            
        } catch (Exception e) {
            log.error("加入房间时出现异常: {}", e.getMessage(), e);
            return new RoomJoinResult(false, "加入房间失败: " + e.getMessage(), null);
        }
    }

    public boolean leaveRoom(Integer heroId) {
        try {
            String playerKey = "game:hero:" + heroId;
            String roomId = (String)this.redisTemplate.opsForValue().get(playerKey);
            if (roomId == null) {
                return false;
            }
            
            String roomKey = "game:room:" + roomId;
            
            this.redisTemplate.opsForSet().remove(roomKey, heroId);
            
            // 获取heroId并删除heroKey
            String playerHashKey = "game:player:" + heroId + ":data";
            Object heroIdObj = this.redisTemplate.opsForHash().get(playerHashKey, "heroId");
            if (heroIdObj != null) {
                String heroKey = "game:hero:" + heroIdObj;
                this.redisTemplate.delete(heroKey);
            }
            
            // 检查是否是金老鼠，如果是则掉落金币
            Object isMouseObj = this.redisTemplate.opsForHash().get(playerHashKey, "isMouse");
            if (isMouseObj != null && (Boolean) isMouseObj) {
                dropMouseCoins(roomId, heroId);
            }
            
            this.redisTemplate.delete(playerKey);
            this.redisTemplate.delete(playerHashKey);
            
            log.info("玩家 {} 离开房间 {}, 剩余人数: {}", heroId, roomId, this.getRoomPlayerCount(roomId));
            
            if (this.getRoomPlayerCount(roomId) == 0) {
                this.redisTemplate.delete(roomKey);
                log.info("房间 {} 已清空，删除房间", roomId);
            }

            return true;
        } catch (Exception e) {
            log.error("离开房间时出现异常: {}", e.getMessage(), e);
            return false;
        }
    }

    public boolean leaveRoomWithCoinDrop(Integer heroId) {
        try {
            String playerKey = "game:hero:" + heroId;
            String roomId = (String)this.redisTemplate.opsForValue().get(playerKey);
            if (roomId == null) {
                return false;
            }
            
            String roomKey = "game:room:" + roomId;
            
            this.redisTemplate.opsForSet().remove(roomKey, heroId);
            
            // 获取heroId并删除heroKey
            String playerHashKey = "game:player:" + heroId + ":data";
            Object heroIdObj = this.redisTemplate.opsForHash().get(playerHashKey, "heroId");
            if (heroIdObj != null) {
                String heroKey = "game:hero:" + heroIdObj;
                this.redisTemplate.delete(heroKey);
            }
            
            boolean droppedCoins = false;
            // 检查是否是金老鼠，如果是则掉落金币
            Object isMouseObj = this.redisTemplate.opsForHash().get(playerHashKey, "isMouse");
            if (isMouseObj != null && (Boolean) isMouseObj) {
                dropMouseCoins(roomId, heroId);
                droppedCoins = true;
            }
            
            this.redisTemplate.delete(playerKey);
            this.redisTemplate.delete(playerHashKey);
            
            log.info("玩家 {} 离开房间 {}, 剩余人数: {}, 是否掉落金币: {}", heroId, roomId, this.getRoomPlayerCount(roomId), droppedCoins);
            
            if (this.getRoomPlayerCount(roomId) == 0) {
                this.redisTemplate.delete(roomKey);
                log.info("房间 {} 已清空，删除房间", roomId);
            }

            return droppedCoins;
        } catch (Exception e) {
            log.error("离开房间时出现异常: {}", e.getMessage(), e);
            return false;
        }
    }

    public List<Player> getPlayersInRoom(String roomId) {
        try {
            String roomKey = "game:room:" + roomId;

            Set<Object> playerIds = this.redisTemplate.opsForSet().members(roomKey);
            if (playerIds == null || playerIds.isEmpty()) {
                return new ArrayList<>();
            }

            List<Player> playerList = new ArrayList<>();

            for (Object obj : playerIds) {
                if (obj instanceof Integer playerId) {
                    Player player = getPlayerById(playerId);
                    if (player != null) {
                        playerList.add(player);
                    }
                }
            }

            return playerList;
        } catch (Exception e) {
            log.error("获取房间玩家时出现异常: {}", e.getMessage(), e);
            return new ArrayList<>();
        }
    }
    
    private Player getPlayerById(Integer playerId) {
        try {
            String playerHashKey = "game:player:" + playerId + ":data";
            
            Map<Object, Object> playerData = this.redisTemplate.opsForHash().entries(playerHashKey);
            if (playerData.isEmpty()) {
                return null;
            }

            Player player = new Player();

            // 设置sessionId
            if (playerData.get("sessionId") != null) {
                player.setSessionId((String) playerData.get("sessionId"));
            }
            // 设置heroId
            if (playerData.get("heroId") != null) {
                player.setHeroId((Integer) playerData.get("heroId"));
            }
            
            // 设置position
            if (playerData.get("position") != null) {
                try {
                    @SuppressWarnings("unchecked")
                    Map<String, Float> positionMap = (Map<String, Float>) playerData.get("position");
                    Float x = positionMap.get("x");
                    Float y = positionMap.get("y");
                    Float z = positionMap.get("z");
                    if (x != null && y != null) {
                        player.setPosition(new Position(x, y, z != null ? z : 0.0f));
                    }
                } catch (Exception e) {
                    log.warn("无法解析位置信息: {}", playerData.get("position"));
                }
            }
            
            // 设置rotation
            if (playerData.get("rotation") != null) {
                try {
                    @SuppressWarnings("unchecked")
                    Map<String, Float> rotationMap = (Map<String, Float>) playerData.get("rotation");
                    Float y = rotationMap.get("y");
                    if (y != null) {
                        Rotation rotation = new Rotation();
                        rotation.setY(y);
                        player.setRotation(rotation);
                    }
                } catch (Exception e) {
                    log.warn("无法解析旋转信息: {}", playerData.get("rotation"));
                }
            }
            
            // 设置animation
            if (playerData.get("animation") != null) {
                player.setAnimation((String) playerData.get("animation"));
            }
            
            // 设置isMouse
            if (playerData.get("isMouse") != null) {
                player.setMouse((Boolean) playerData.get("isMouse"));
            }
            
            return player;
        } catch (Exception e) {
            log.error("获取玩家数据时出现异常: {}", e.getMessage(), e);
            return null;
        }
    }

    public int getRoomPlayerCount(String roomId) {
        try {
            // game:room:roomId  是一个set ，里面存放的是 heroId
            String roomKey = "game:room:" + roomId;
            Long size = this.redisTemplate.opsForSet().size(roomKey);  // 返回set的大小，即房间的人数
            return size != null ? size.intValue() : 0;
        } catch (Exception e) {
            log.error("获取房间人数时出现异常: {}", e.getMessage(), e);
            return 0;
        }
    }


    public List<String> getAllRoomIds() {
        try {
            List<String> roomIds = new ArrayList<>();
            Set<String> keys = this.redisTemplate.keys("game:room:*");
            if (keys != null) {
                for(String key : keys) {
                    if (!key.endsWith(":counter") && !key.endsWith(":mouse")) {
                        String roomId = key.substring("game:room:".length());
                        if (!"counter".equals(roomId) && !roomId.contains(":")) {
                            roomIds.add(roomId);
                        }
                    }
                }
            }
            return roomIds;
        } catch (Exception e) {
            log.error("获取所有房间ID时出现异常: {}", e.getMessage(), e);
            return new ArrayList<>();
        }
    }

    public boolean updatePlayerPosition(Integer heroId, Player updatedPlayer) {
        try {
            String playerKey = "game:hero:" + heroId;
            String roomId = (String)this.redisTemplate.opsForValue().get(playerKey);
            if (roomId == null) {
                return false;
            }
            
            String roomKey = "game:room:" + roomId;
            
            Boolean isMember = this.redisTemplate.opsForSet().isMember(roomKey, heroId);
            if (!Boolean.TRUE.equals(isMember)) {
                log.warn("玩家 {} 不在房间 {} 中，无法更新位置", heroId, roomId);
                return false;
            }
            
            String playerHashKey = "game:player:" + heroId + ":data";
            
            // 只更新有用的字段：position, rotation, animation
            Position pos = updatedPlayer.getPosition();
            if (pos != null) {
                Map<String, Float> positionMap = new HashMap<>();
                positionMap.put("x", pos.getX());
                positionMap.put("y", pos.getY());
                positionMap.put("z", pos.getZ());
                this.redisTemplate.opsForHash().put(playerHashKey, "position", positionMap);
            }
            
            // 更新旋转信息
            Rotation rotation = updatedPlayer.getRotation();
            if (rotation != null) {
                Map<String, Float> rotationMap = new HashMap<>();
                rotationMap.put("y", rotation.getY());
                this.redisTemplate.opsForHash().put(playerHashKey, "rotation", rotationMap);
            }
            
            // 更新动画信息
            if (updatedPlayer.getAnimation() != null) {
                this.redisTemplate.opsForHash().put(playerHashKey, "animation", updatedPlayer.getAnimation());
            }
            
            
            return true;
        } catch (Exception e) {
            log.error("更新玩家位置时出现异常: {}", e.getMessage(), e);
            return false;
        }
    }

    // todo 玩家加入一定要能够分配到房间，不要返回房间满了（如果两个玩家同时找到一个还剩1名额的房间，那么会有一个玩家加入房间失败）
    private String findAvailableRoom() {
        try {
            Set<String> keys = this.redisTemplate.keys("game:room:*");
            String targetRoomId = null;
            int maxPlayers = 0;
            if (keys != null) {
                for(String key : keys) {
                    if (key.endsWith(":counter") || key.endsWith(":mouse")) {
                        continue;
                    }

                    String roomId = key.substring("game:room:".length());
                    if (!"counter".equals(roomId) && !roomId.contains(":")) {
                        int playerCount = this.getRoomPlayerCount(roomId);  // 获取该房间的人数
                        if (playerCount < 5 && playerCount >= maxPlayers) {
                            maxPlayers = playerCount;
                            targetRoomId = roomId;
                        }
                    }
                }
            }

            return targetRoomId;
        } catch (Exception e) {
            log.error("寻找可用房间时出现异常: {}", e.getMessage(), e);
            return null;
        }
    }

    private String createNewRoom() {
        try {
            if (!Boolean.TRUE.equals(this.redisTemplate.hasKey("game:room:counter"))) {
                this.redisTemplate.opsForValue().set("game:room:counter", 0L);   // 创建房间计数器
            }

            Long roomNumber = this.redisTemplate.opsForValue().increment("game:room:counter");
            String roomId = "Room_" + roomNumber;
            String roomKey = "game:room:" + roomId;
            
            this.redisTemplate.expire(roomKey, 3L, TimeUnit.DAYS);   // 创建房间的 key ，并设置三天过期时间
            return roomId;
        } catch (Exception e) {
            log.error("创建新房间时出现异常: {}", e.getMessage(), e);
            return "Room_" + System.currentTimeMillis();
        }
    }



    /**
     * 定时任务分配金老鼠给指定玩家
     */
    public boolean assignMouseToPlayer(String roomId, Integer heroId) {
        try {
            String mouseKey = "game:room:" + roomId + ":mouse";
            
            // 检查玩家是否在房间中
            String roomKey = "game:room:" + roomId;
            Boolean isMember = this.redisTemplate.opsForSet().isMember(roomKey, heroId);
            if (!Boolean.TRUE.equals(isMember)) {
                log.warn("玩家 {} 不在房间 {} 中，无法分配金老鼠", heroId, roomId);
                return false;
            }
            
            // 使用原子操作设置金老鼠，如果key已存在则返回false
            Boolean setResult = this.redisTemplate.opsForValue().setIfAbsent(mouseKey, heroId);
            if (!Boolean.TRUE.equals(setResult)) {
                // 房间已有金老鼠，无法分配新金老鼠
                Object existingMouse = this.redisTemplate.opsForValue().get(mouseKey);
                log.debug("房间 {} 已有金老鼠 {}，无法分配新金老鼠", roomId, existingMouse);
                return false;
            }
            
            // 设置过期时间
            this.redisTemplate.expire(mouseKey, 3L, TimeUnit.DAYS);
            
            // 初始化金老鼠的金币数量
            String mouseCoinKey = "game:mouse:" + heroId + ":coins";
            this.redisTemplate.opsForValue().set(mouseCoinKey, 10);
            this.redisTemplate.expire(mouseCoinKey, 3L, TimeUnit.DAYS);
            
            // 更新玩家数据中的金老鼠标记
            String playerHashKey = "game:player:" + heroId + ":data";
            this.redisTemplate.opsForHash().put(playerHashKey, "isMouse", true);
            
            log.info("定时任务成功分配玩家 {} 为金老鼠，房间: {}", heroId, roomId);
            return true;
        } catch (Exception e) {
            log.error("定时任务分配金老鼠失败", e);
            return false;
        }
    }

    /**
     * 获取房间的金老鼠ID
     */
    public Integer getRoomMouse(String roomId) {
        try {
            // key: game:room:Room_1:mouse  value: heroId
            String mouseKey = "game:room:" + roomId + ":mouse";
            Object mouseId = this.redisTemplate.opsForValue().get(mouseKey);
            return mouseId != null ? (Integer) mouseId : null;
        } catch (Exception e) {
            log.error("获取房间金老鼠失败", e);
            return null;
        }
    }

    /**
     * 获取金老鼠的金币数量
     */
    public Integer getMouseCoinCount(Integer heroId) {
        try {
            // key: game:mouse:1:coins    value: 10
            String mouseCoinKey = "game:mouse:" + heroId + ":coins";
            Object coinCount = this.redisTemplate.opsForValue().get(mouseCoinKey);
            return coinCount != null ? (Integer) coinCount : 0;
        } catch (Exception e) {
            log.error("获取金老鼠金币数量失败", e);
            return 0;
        }
    }


    /**
     * 金老鼠离开房间，掉落所有金币
     */
    public void dropMouseCoins(String roomId, Integer heroId) {
        try {
            String mouseCoinKey = "game:mouse:" + heroId + ":coins";
            Object coinCountObj = this.redisTemplate.opsForValue().get(mouseCoinKey);  // 金老鼠身上剩余的金币
            
            if (coinCountObj != null) {
                Integer coinCount = (Integer) coinCountObj;
                
                // 生成掉落的金币
                for (int i = 0; i < coinCount; i++) {
                    String coinId = "coin_" + System.currentTimeMillis() + "_" + i;
                    createDroppedCoin(roomId, coinId, i);
                }
                
                // 删除金老鼠的金币记录
                this.redisTemplate.delete(mouseCoinKey);
                
                // 清除金老鼠标记
                String mouseKey = "game:room:" + roomId + ":mouse";
                this.redisTemplate.delete(mouseKey);
                
                log.info("金老鼠 {} 离开房间 {}，掉落 {} 个金币", heroId, roomId, coinCount);
            }
        } catch (Exception e) {
            log.error("金老鼠掉落金币失败", e);
        }
    }

    /**
     * 创建掉落的金币
     */
    private void createDroppedCoin(String roomId, String coinId, int position) {
        try {
            String coinKey = "coin:" + coinId;
            Map<String, Object> coinData = new HashMap<>();
            coinData.put("id", coinId);
            coinData.put("money", "1");
            coinData.put("position", String.valueOf(position));
            coinData.put("roomId", roomId);
            // 不存储heroId字段，表示未被抢走
            
            this.redisTemplate.opsForHash().putAll(coinKey, coinData);
            this.redisTemplate.expire(coinKey, 3L, TimeUnit.DAYS);
            
            // 添加到房间金币集合
            String roomCoinsKey = "room:coins:" + roomId;
            this.redisTemplate.opsForSet().add(roomCoinsKey, coinId);
            this.redisTemplate.expire(roomCoinsKey, 3L, TimeUnit.DAYS);
            
            // 添加到位置映射
            String roomCoinPositionKey = "room:coin_position:" + roomId;
            this.redisTemplate.opsForHash().put(roomCoinPositionKey, coinId, String.valueOf(position));
            this.redisTemplate.expire(roomCoinPositionKey, 3L, TimeUnit.DAYS);
            
        } catch (Exception e) {
            log.error("创建掉落金币失败", e);
        }
    }

    /**
     * 获取房间内掉落的金币位置信息
     */
    public List<Map<String, Object>> getRoomDroppedCoins(String roomId) {
        try {
            String roomCoinsKey = "room:coins:" + roomId;
            Set<Object> coinIds = this.redisTemplate.opsForSet().members(roomCoinsKey);
            
            if (coinIds == null || coinIds.isEmpty()) {
                return new ArrayList<>();
            }
            
            List<Map<String, Object>> coins = new ArrayList<>();
            for (Object coinId : coinIds) {
                String coinKey = "coin:" + coinId;
                Map<Object, Object> coinData = this.redisTemplate.opsForHash().entries(coinKey);
                
                if (!coinData.isEmpty()) {
                    String heroId = (String) coinData.get("heroId");
                    if (heroId == null || heroId.trim().isEmpty()) {
                        Map<String, Object> coin = new HashMap<>();
                        // 确保position是数字类型
                        String positionStr = (String) coinData.get("position");
                        try {
                            coin.put("position", Integer.parseInt(positionStr));
                        } catch (NumberFormatException e) {
                            coin.put("position", 0);
                        }
                        coin.put("id", coinId);
                        coins.add(coin);
                    }
                }
            }
            
            return coins;
        } catch (Exception e) {
            log.error("获取房间掉落金币失败", e);
            return new ArrayList<>();
        }
    }

    /**
     * 抢金老鼠的金币（带锁机制）
     */
    public boolean grabMouseCoin(String roomId, Integer heroId) {
        ReentrantLock lock = roomLocks.computeIfAbsent(roomId, k -> new ReentrantLock());
        
        try {
            // 尝试获取锁，最多等待100毫秒
            if (lock.tryLock(100, TimeUnit.MILLISECONDS)) {
                try {
                    return doGrabMouseCoin(roomId, heroId);
                } finally {
                    lock.unlock();
                }
            } else {
                log.warn("玩家 {} 抢金币失败，房间 {} 正在处理其他抢金币请求", heroId, roomId);
                return false;
            }
        } catch (InterruptedException e) {
            log.error("抢金币时被中断", e);
            Thread.currentThread().interrupt();
            return false;
        } catch (Exception e) {
            log.error("抢金币失败", e);
            return false;
        }
    }

    /**
     * 执行抢金币逻辑
     */
    private boolean doGrabMouseCoin(String roomId, Integer heroId) {
        try {
            // 检查房间是否有金老鼠
            Integer mouseHeroId = getRoomMouse(roomId);
            if (mouseHeroId == null) {
                log.debug("房间 {} 没有金老鼠，无法抢金币", roomId);
                return false;
            }

            // 检查金老鼠是否在冷却中
            String coolDownKey = "game:room:" + roomId + ":cooldown";
            if (Boolean.TRUE.equals(redisTemplate.hasKey(coolDownKey))) {
                log.debug("房间 {} 的金老鼠正在冷却中，无法抢金币", roomId);
                return false;
            }

            // 检查金老鼠是否有金币
            String mouseCoinKey = "game:mouse:" + mouseHeroId + ":coins";
            Object coinCountObj = redisTemplate.opsForValue().get(mouseCoinKey);
            if (coinCountObj == null) {
                log.debug("金老鼠 {} 没有金币", mouseHeroId);
                return false;
            }

            Integer coinCount = (Integer) coinCountObj;
            if (coinCount <= 0) {
                log.debug("金老鼠 {} 金币数量为0", mouseHeroId);
                return false;
            }

            // 减少金老鼠的金币数量
            Long newCount = redisTemplate.opsForValue().decrement(mouseCoinKey);
            if (newCount != null && newCount >= 0) {
                log.info("玩家 {} 成功抢到金老鼠 {} 的金币，剩余金币: {}", heroId, mouseHeroId, newCount);
                
                // 记录玩家抢到的金老鼠金币
                recordMouseCoinGrab(heroId);
                
                return true;
            } else {
                log.warn("抢金币失败，金老鼠 {} 金币数量异常", mouseHeroId);
                return false;
            }
        } catch (Exception e) {
            log.error("执行抢金币逻辑失败", e);
            return false;
        }
    }

    /**
     * 获取房间金老鼠的金币数量
     */
    public Integer getRoomMouseCoinCount(String roomId) {
        try {
            Integer mouseHeroId = getRoomMouse(roomId);
            if (mouseHeroId == null) {
                return 0;
            }
            return getMouseCoinCount(mouseHeroId);
        } catch (Exception e) {
            log.error("获取房间金老鼠金币数量失败", e);
            return 0;
        }
    }

    /**
     * 设置房间冷却状态
     */
    public void setRoomCooldown(String roomId) {
        try {
            String coolDownKey = "game:room:" + roomId + ":cooldown";
            redisTemplate.opsForValue().set(coolDownKey, true, 500, TimeUnit.MILLISECONDS);
        } catch (Exception e) {
            log.error("设置房间冷却状态失败", e);
        }
    }

    /**
     * 抢地面金币
     */
    public boolean grabGroundCoin(String roomId, String coinId, Integer heroId) {
        try {
            String coinKey = "coin:" + coinId;
            
            // 检查金币是否存在
            if (!Boolean.TRUE.equals(redisTemplate.hasKey(coinKey))) {
                log.debug("金币 {} 不存在", coinId);
                return false;
            }
            
            // 检查金币是否已被抢走
            String heroIdStr = (String) redisTemplate.opsForHash().get(coinKey, "heroId");
            if (heroIdStr != null && !heroIdStr.trim().isEmpty()) {
                log.debug("金币 {} 已被抢走，当前heroId: {}", coinId, heroIdStr);
                return false;
            }
            
            // 使用Redis的原子操作设置heroId
            // 如果heroId字段不存在或为空字符串，则设置新的heroId
            Boolean success = redisTemplate.opsForHash().putIfAbsent(coinKey, "heroId", heroId.toString());
            if (Boolean.TRUE.equals(success)) {
                log.info("玩家 {} 成功抢到地面金币 {}", heroId, coinId);
                return true;
            } else {
                log.debug("金币 {} 抢取失败，可能已被其他玩家抢走", coinId);
                return false;
            }
        } catch (Exception e) {
            log.error("抢地面金币失败", e);
            return false;
        }
    }

    /**
     * 获取房间内剩余的地面金币数量
     */
    public Integer getRoomDroppedCoinsCount(String roomId) {
        try {
            String roomCoinsKey = "room:coins:" + roomId;
            Set<Object> coinIds = redisTemplate.opsForSet().members(roomCoinsKey);
            
            if (coinIds == null || coinIds.isEmpty()) {
                return 0;
            }
            
            int availableCount = 0;
            for (Object coinId : coinIds) {
                String coinKey = "coin:" + coinId;
                String heroId = (String) redisTemplate.opsForHash().get(coinKey, "heroId");
                if (heroId == null || heroId.trim().isEmpty()) {
                    availableCount++;
                }
            }
            
            return availableCount;
        } catch (Exception e) {
            log.error("获取房间地面金币数量失败", e);
            return 0;
        }
    }

    /**
     * 记录玩家抢到的金老鼠金币
     */
    private void recordMouseCoinGrab(Integer heroId) {
        try {
            String grabKey = "game:player:" + heroId + ":mouse_coins";
            redisTemplate.opsForValue().increment(grabKey);
            log.debug("记录玩家 {} 抢到金老鼠金币", heroId);
        } catch (Exception e) {
            log.error("记录玩家 {} 抢金老鼠金币失败", heroId, e);
        }
    }

    /**
     * 获取玩家抢到的金老鼠金币数量
     */
    public Integer getPlayerMouseCoins(Integer heroId) {
        try {
            String grabKey = "game:player:" + heroId + ":mouse_coins";
            Object count = redisTemplate.opsForValue().get(grabKey);
            return count != null ? (Integer) count : 0;
        } catch (Exception e) {
            log.error("获取玩家 {} 金老鼠金币数量失败", heroId, e);
            return 0;
        }
    }

    /**
     * 获取玩家抢到的地面金币数量
     */
    public Integer getPlayerGroundCoins(Integer heroId) {
        try {
            Set<String> coinKeys = redisTemplate.keys("coin:*");
            if (coinKeys == null || coinKeys.isEmpty()) {
                return 0;
            }
            
            int count = 0;
            for (String coinKey : coinKeys) {
                String heroIdStr = (String) redisTemplate.opsForHash().get(coinKey, "heroId");
                if (heroIdStr != null && heroIdStr.equals(heroId.toString())) {
                    count++;
                }
            }
            return count;
        } catch (Exception e) {
            log.error("获取玩家 {} 地面金币数量失败", heroId, e);
            return 0;
        }
    }

    /**
     * 获取玩家总金币数量（金老鼠金币 + 地面金币）
     */
    public Integer getPlayerTotalCoins(Integer heroId) {
        Integer mouseCoins = getPlayerMouseCoins(heroId);
        Integer groundCoins = getPlayerGroundCoins(heroId);
        return mouseCoins + groundCoins;
    }

    /**
     * 获取所有玩家的金币统计
     */
    public Map<Integer, Integer> getAllPlayersCoinStats() {
        Map<Integer, Integer> playerCoins = new HashMap<>();
        try {
            // 获取所有玩家数据
            Set<String> playerDataKeys = redisTemplate.keys("game:player:*:data");
            if (playerDataKeys != null) {
                for (String playerDataKey : playerDataKeys) {
                    try {
                        Object heroIdObj = redisTemplate.opsForHash().get(playerDataKey, "heroId");
                        if (heroIdObj != null) {
                            Integer heroId;
                            if (heroIdObj instanceof Integer) {
                                heroId = (Integer) heroIdObj;
                            } else if (heroIdObj instanceof String) {
                                heroId = Integer.parseInt((String) heroIdObj);
                            } else {
                                log.warn("玩家数据 {} 中的heroId类型不正确: {}", playerDataKey, heroIdObj.getClass());
                                continue;
                            }
                            
                            Integer totalCoins = getPlayerTotalCoins(heroId);
                            if (totalCoins > 0) {
                                playerCoins.put(heroId, totalCoins);
                            }
                        }
                    } catch (Exception e) {
                        log.warn("处理玩家数据 {} 时出错: {}", playerDataKey, e.getMessage());
                    }
                }
            }
        } catch (Exception e) {
            log.error("获取所有玩家金币统计失败", e);
        }
        return playerCoins;
    }

    /**
     * 持久化所有玩家的金币到用户表
     */
    public void persistAllPlayerCoins() {
        try {
            log.info("开始持久化所有玩家的金币到用户表");
            
            Map<Integer, Integer> playerCoins = getAllPlayersCoinStats();
            int successCount = 0;
            int failCount = 0;
            
            for (Map.Entry<Integer, Integer> entry : playerCoins.entrySet()) {
                Integer heroId = entry.getKey();
                Integer coinCount = entry.getValue();
                
                try {
                    int updated = userMapper.updateBalanceByHeroId(heroId, coinCount);
                    if (updated > 0) {
                        log.info("成功更新用户 {} 的余额，增加金币: {}", heroId, coinCount);
                        successCount++;
                    } else {
                        log.warn("用户 {} 不存在，无法更新余额", heroId);
                        failCount++;
                    }
                } catch (Exception e) {
                    log.error("更新用户 {} 余额失败", heroId, e);
                    failCount++;
                }
            }
            
            log.info("金币持久化完成，成功: {}, 失败: {}", successCount, failCount);
        } catch (Exception e) {
            log.error("持久化玩家金币失败", e);
        }
    }

    /**
     * 检查房间游戏是否结束（所有金币都被抢完）
     */
    public boolean isRoomGameEnded(String roomId) {
        try {
            // 检查金老鼠是否还有金币
            Integer mouseHeroId = getRoomMouse(roomId);
            if (mouseHeroId != null) {
                String mouseCoinKey = "game:mouse:" + mouseHeroId + ":coins";
                Object coinCountObj = redisTemplate.opsForValue().get(mouseCoinKey);
                if (coinCountObj != null) {
                    Integer coinCount = (Integer) coinCountObj;
                    if (coinCount > 0) {
                        return false; // 金老鼠还有金币，游戏未结束
                    }
                }
            }
            
            // 检查地面是否还有金币
            Integer groundCoinsCount = getRoomDroppedCoinsCount(roomId);
            if (groundCoinsCount > 0) {
                return false; // 地面还有金币，游戏未结束
            }
            
            // 金老鼠没有金币且地面也没有金币，游戏结束
            return true;
        } catch (Exception e) {
            log.error("检查房间 {} 游戏是否结束失败", roomId, e);
            return false;
        }
    }

    /**
     * 获取房间内所有玩家的金币统计
     */
    public Map<Integer, Integer> getRoomPlayersCoinStats(String roomId) {
        Map<Integer, Integer> playerCoins = new HashMap<>();
        try {
            List<Player> players = getPlayersInRoom(roomId);
            for (Player player : players) {
                Integer heroId = player.getHeroId();
                Integer totalCoins = getPlayerTotalCoins(heroId);
                if (totalCoins > 0) {
                    playerCoins.put(heroId, totalCoins);
                }
            }
        } catch (Exception e) {
            log.error("获取房间 {} 玩家金币统计失败", roomId, e);
        }
        return playerCoins;
    }

    /**
     * 处理金老鼠剩余金币 - 如果金老鼠还有剩余金币，归金老鼠所有
     */
    public void handleMouseRemainingCoins() {
        try {
            log.info("开始处理金老鼠剩余金币");
            
            // 获取所有房间的金老鼠
            Set<String> roomMouseKeys = redisTemplate.keys("game:room:*:mouse");
            if (roomMouseKeys != null) {
                for (String roomMouseKey : roomMouseKeys) {
                    try {
                        Integer mouseHeroId = (Integer) redisTemplate.opsForValue().get(roomMouseKey);
                        
                        if (mouseHeroId != null) {
                            // 检查金老鼠是否还有剩余金币
                            String mouseCoinKey = "game:mouse:" + mouseHeroId + ":coins";
                            Object coinCountObj = redisTemplate.opsForValue().get(mouseCoinKey);
                            
                            if (coinCountObj != null) {
                                Integer remainingCoins = (Integer) coinCountObj;
                                if (remainingCoins > 0) {
                                    log.info("金老鼠 {} 还有 {} 个剩余金币，归其所有", mouseHeroId, remainingCoins);
                                    
                                    // 将剩余金币添加到金老鼠的金币抢取记录中
                                    String grabKey = "game:player:" + mouseHeroId + ":mouse_coins";
                                    redisTemplate.opsForValue().increment(grabKey, remainingCoins);
                                    
                                    log.info("金老鼠 {} 获得剩余金币 {} 个", mouseHeroId, remainingCoins);
                                }
                            }
                        }
                    } catch (Exception e) {
                        log.warn("处理房间 {} 金老鼠剩余金币失败: {}", roomMouseKey, e.getMessage());
                    }
                }
            }
            
            log.info("金老鼠剩余金币处理完成");
        } catch (Exception e) {
            log.error("处理金老鼠剩余金币失败", e);
        }
    }


}
